<template>
  <view style="position: relative; touch-action: none; touch-action: pan-y">
    <view
      class="verify-img-out"
      :style="{ height: parseInt(props.imgSize.height) + props.vSpace + 'px' }"
    >
      <view
        class="verify-img-panel"
        :style="{
          width: props.imgSize.width + 'px',
          height: props.imgSize.height + 'px',
        }"
      >
        <image
          :src="data.backImgBase"
          style="width: 100%; height: 100%; display: block"
        ></image>
        <view
          class="verify-sub-block"
          :style="{
            width: blockSize.width + 'px',
            height: props.imgSize.height + 'px',
            top: '0px',
            left: data.moveBlockLeft,
          }"
        >
          <image
            :src="data.blockBackImgBase"
            style="width: 100%; height: 100%; display: block"
          ></image>
        </view>

        <view
          class="verify-refresh icon-refresh"
          @click="refresh"
          v-show="data.showRefresh"
        >
        </view>

        <text
          class="verify-tips"
          v-if="data.tipWords"
          :class="data.passFlag ? 'suc-bg' : 'err-bg'"
          >{{ data.tipWords }}</text
        >
      </view>
    </view>

    <!-- 公共部分 -->
    <view
      class="verify-bar-area"
      :style="{
        width: props.imgSize.width + 'px',
        height: '40px',
        'line-height': '40px',
      }"
    >
      <text class="verify-msg" v-text="data.text"></text>
      <view
        class="verify-left-bar"
        :style="{
          width: data.leftBarWidth ? data.leftBarWidth : '40px',
          height: '40px',
          'border-color': data.leftBarBorderColor,
        }"
      >
        <text class="verify-msg" v-text="data.finishText"></text>
        <view
          class="verify-move-block"
          @touchstart="start"
          @mousedown="start"
          @touchend="end"
          @touchmove="move"
          :style="{
            width: blockSize.width + 'px',
            height: '40px',
            'background-color': data.moveBlockBackgroundColor,
            left: data.moveBlockLeft,
          }"
        >
          <text
            :class="['verify-icon', data.iconClass]"
            :style="{ color: data.iconColor }"
          ></text>
        </view>
      </view>
    </view>
  </view>
</template>
<script setup lang="ts">
/**
 * VerifySlide
 * @description 滑块
 * */
import {
  ref,
  reactive,
  onMounted,
  onUnmounted,
  watch,
  computed,
  getCurrentInstance,
} from "vue";
import { aesEncrypt } from "./../utils/ase.js";
import { myRequest } from "../utils/request.js";
defineOptions({
  name: "VerifySlide",
});
let emit = defineEmits(["success", "error"]);

const props = defineProps({
  captchaType: {
    type: String,
    default: "",
  },

  vSpace: {
    type: Number,
    default: 5,
  },
  explain: {
    type: String,
    default: "向右滑动完成验证",
  },
  imgSize: {
    type: Object,
    default: () => ({
      width: 310,
      height: 155,
    }),
  },
  blockSize: {
    type: Object,
    default: () => ({
      // width: 47,
      height: 47,
    }),
  },
});
const blockSize = computed(() => {
  return {
    width: (props.imgSize.width / 310) * 47,
    height: props.blockSize.height,
  };
});
// Data 定义
const data = reactive({
  secretKey: "", //后端返回的加密秘钥 字段
  passFlag: false, //请求通过与否
  backImgBase: "", //验证码背景图片
  blockBackImgBase: "", //验证滑块的背景图片
  backToken: "", //后端返回的唯一token值
  startMoveTime: 0, //移动开始的时间
  endMovetime: 0, //移动结束的时间
  tipsBackColor: "", //提示词的北京颜色
  tipWords: "",
  text: props.explain,
  finishText: "",
  setSize: {
    imgHeight: 0,
    imgWidth: 0,
    barHeight: 0,
    barWidth: 0,
  },
  top: 0,
  left: 0,
  moveBlockLeft: "",
  leftBarWidth: "",
  // 移动中样式
  moveBlockBackgroundColor: undefined,
  leftBarBorderColor: "#ddd",
  iconColor: undefined,
  iconClass: "icon-right",
  status: false, //鼠标状态
  isEnd: false, //是够验证完成
  showRefresh: true,
});

let startLeft = ref(0);
const start = (e) => {
  // ... 鼠标按下逻辑
  // console.log('e',e);

  data.startMoveTime = new Date().getTime(); //开始滑动的时间
  if (data.isEnd == false) {
    data.text = "";
    data.moveBlockBackgroundColor = "#337ab7";
    data.leftBarBorderColor = "#337AB7";
    data.iconColor = "#fff";
    e.stopPropagation();
    data.status = true;
    if (!e.touches) {
      //兼容移动端
      startLeft.value = Math.ceil(e.clientX);
    } else {
      //兼容PC端
      startLeft.value = Math.ceil(e.touches[0].pageX);
    }
  }
};

// const appInstance = getCurrentInstance().proxy;

const move = (e) => {
  e.stopPropagation();
  if (data.status == true) {
    if (!e.touches) {
      //兼容移动端
      var x = Math.ceil(e.clientX);
    } else {
      //兼容PC端
      var x = Math.ceil(e.touches[0].pageX);
    }
    let left = x - startLeft.value; //小方块相对于父元素的left值
    // console.log("left", left);
    if (left < 0) {
      left = 0;
    }

    if (left >= props.imgSize.width - blockSize.value.width) {
      left = props.imgSize.width - blockSize.value.width;
    }

    //拖动后小方块的left值
    data.moveBlockLeft = left + "px";
    data.leftBarWidth = left + "px";

    return;
  }
};

const end = (e) => {
  e.stopPropagation();
  console.log('end');
  
  // ... 鼠标松开逻辑
  data.endMovetime = new Date().getTime();

  //                判断是否重合
  if (data.status && data.isEnd == false) {
    var moveLeftDistance = parseInt(
      (data.moveBlockLeft || "").replace("px", "")
    );

    moveLeftDistance = (moveLeftDistance * 310) / parseInt(props.imgSize.width);

    // var captchaVerification = this.secretKey ?aesEncrypt(this.backToken+'---'+JSON.stringify({x:moveLeftDistance,y:5.0}),this.secretKey):this.backToken+'---'+JSON.stringify({x:moveLeftDistance,y:5.0})
    let sendData = {
      captchaType: props.captchaType,
      pointJson: data.secretKey
        ? aesEncrypt(
            JSON.stringify({
              x: moveLeftDistance,
              y: 5.0,
            }),
            data.secretKey
          )
        : JSON.stringify({
            x: moveLeftDistance,
            y: 5.0,
          }),
      token: data.backToken,
    };
    myRequest({
      url: `/captcha/check`,
      data: sendData,
      method: "POST",
    })
      .then((result) => {
        let res = result.data;
        data.showRefresh = true;
        data.status = false;
        data.isEnd = true;
        if (res.repCode == "0000") {
          data.moveBlockBackgroundColor = "#5cb85c";
          data.leftBarBorderColor = "#5cb85c";
          data.iconColor = "#fff";
          data.iconClass = "icon-check";

          setTimeout(() => {
            refresh();
          }, 1000);
          data.passFlag = true;
          data.tipWords = `${(
            (data.endMovetime - data.startMoveTime) /
            1000
          ).toFixed(2)}s验证成功`;
          setTimeout(() => {
            data.tipWords = "";
            emit("success", {
              ...sendData,
            });
          }, 500);
        } else {
          data.moveBlockBackgroundColor = "#d9534f";
          data.leftBarBorderColor = "#d9534f";
          data.iconColor = "#fff";
          data.iconClass = "icon-close";
          data.passFlag = false;
          setTimeout(() => {
            refresh();
          }, 1000);
          emit("error");
          data.tipWords = "验证失败";
          setTimeout(() => {
            data.tipWords = "";
          }, 1000);
        }
      })
      .catch((err) => {
        data.status = false;
        data.isEnd = true;
        console.log(err);
      });
  }
};

const refresh = () => {
  // ... 刷新验证码逻辑
  data.showRefresh = true;
  data.finishText = "";

  data.moveBlockLeft = "0";
  data.leftBarWidth = "";

  data.leftBarBorderColor = "#ddd";
  data.moveBlockBackgroundColor = "#fff";
  data.iconColor = "#000";
  data.iconClass = "icon-right";
  getPictrue();
  data.isEnd = false;
  setTimeout(() => {
    data.text = props.explain;
  }, 300);
};

const getPictrue = () => {
  // ... 请求背景图片和验证图片逻辑
  let sendData = {
    captchaType: props.captchaType,
    ts: Date.now(), // 现在的时间戳
  };
  myRequest({
    url: "/captcha/get", //仅为示例，并非真实接口地址。
    data: sendData,
    method: "POST",
  }).then((result) => {
    let res = result.data;
    if (res.repCode == "0000") {
      data.backImgBase =
        "data:image/png;base64," + res.repData.originalImageBase64;
      // console.log('this.backImgBase',this.backImgBase);
      console.log("this.backImgBase");
      data.blockBackImgBase =
        "data:image/png;base64," + res.repData.jigsawImageBase64;
      // console.log('this.blockBackImgBase',this.blockBackImgBase);

      data.backToken = res.repData.token;
      data.secretKey = res.repData.secretKey;
    }
    // 判断接口请求次数是否失效
    if (res.repCode == "6201") {
      data.backImgBase = null;
      data.blockBackImgBase = null;
    }
  });
};

// Methods 定义
const init = () => {
  data.text = props.explain;
  getPictrue();

  // #ifdef WEB
  // window.removeEventListener("touchmove",move);
  // window.removeEventListener("mousemove",move);

  window.addEventListener("touchmove", move);
  window.addEventListener("mousemove", move);

  //鼠标松开
  window.addEventListener("touchend", end);
  window.addEventListener("mouseup", end);
  // #endif
};
// 组件挂载时调用
onMounted(() => {
  init();
});
onUnmounted(() => {
  // #ifdef WEB
  window.removeEventListener("touchmove", move);
  window.removeEventListener("mousemove", move);
  window.removeEventListener("touchend", end);
  window.removeEventListener("mouseup", end);
  // #endif
});

defineExpose({
  refresh,
});
</script>
<style scoped>
.verify-tips {
  position: absolute;
  left: 0px;
  bottom: 0px;
  width: 100%;
  height: 30px;
  background-color: rgb(231, 27, 27, 0.5);
  line-height: 30px;
  color: #fff;
}

.suc-bg {
  background-color: rgba(92, 184, 92, 0.5);
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
}

.err-bg {
  background-color: rgba(217, 83, 79, 0.5);
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
}

/*滑动验证码*/
.verify-bar-area {
  position: relative;
  background: #ffffff;
  text-align: center;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
}

.verify-bar-area .verify-move-block {
  position: absolute;
  top: 0px;
  left: 0;
  background: #fff;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  box-shadow: 0 0 2px #888888;
}

.verify-bar-area .verify-move-block:hover {
  background-color: #337ab7;
  color: #ffffff;
}

.verify-bar-area .verify-left-bar {
  position: absolute;
  top: -1px;
  left: -1px;
  background: #f0fff0;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
}

.verify-img-panel {
  margin: 0;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border-top: 1px solid #ddd;
  border-bottom: 1px solid #ddd;
  border-radius: 3px;
  position: relative;
}

.verify-img-panel .verify-refresh {
  width: 25px;
  height: 25px;
  text-align: center;
  padding: 5px;
  cursor: pointer;
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
}

.verify-img-panel .icon-refresh {
  font-size: 20px;
  color: #fff;
}

.verify-img-panel .verify-gap {
  background-color: #fff;
  position: relative;
  z-index: 2;
  border: 1px solid #fff;
}

.verify-img-panel .verify-sub-block {
  position: absolute;
  /* text-align: center; */
  top: 0;
  z-index: 3;
  /* border: 1px solid #fff; */
}

.verify-bar-area .verify-move-block .verify-icon {
  font-size: 18px;
}

.verify-bar-area .verify-msg {
  z-index: 3;
}

.icon-check:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}

.icon-close:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}

.icon-right:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background-size: cover;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}

.icon-refresh:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}
</style>
